/* MFZPSP:     gui/win/win.c               *
 * Created by: Stefan Zurfluh              *
 * Edited by:  - S. Z.                     *
 *             - Mauro Frischherz          */

#ifdef GUI_WINDOWS

#include "win.h"

uintptr_t GUIThread;

  HDC GDIDevice;
  PAINTSTRUCT PaintStruct;
  HFONT FStatusBar, FTitle, FHex, FMonospace;
  HBRUSH BLightBlue, BDarkBlue, BLightGray, BMediumGray, BRed, BBlack, BYellow;
  HPALETTE BMPPalette;
  HBITMAP IStatusYellow, IStatusRed, IStatusGray, IStatusBlue, IStatusGreen, IPlayI, IPlayA, IPauseI,
  	IPauseA, IStopI, IStopA, IOpenA, IOpenI;
  short OverButton = 0, ClickButton = 0;

    HWND ToolBar[NUM_TOOLBAR_BUTTONS];
    RECT RClientArea;
    RECT RStatusBar, RDisplay, RRegisters, RMemory, RDisasm;

      RECT _RRegisters1, _RRegisters2;
      unsigned short RegistersPos = 0;
      unsigned long oldRegister[33];
      bool RegistersToZoom = false;
      short ScrollReg = 0;
      
      RECT _RDisasm1, _RDisasm2;
      long DisasmPos = -1;
      short ScrollDisasm = 0;

      bool BlinkEnabled = false, Blinking = false;

      bool ExtendedView = true;

int GUIStart()
{
	// Creating a new thread with 64 kBytes stack size.
	
	GUIThread = (uintptr_t)_beginthread(GUI, 65535, NULL);
	
	if(!GUIThread)
		printerror("Could not create GUI thread.");
	else
		printevent("Main windowthread created successfully.");
	
	return (int)GUIThread;
}

void GUI()
{
	MSG msg;
	
	CreateMainWin();
	
	while (GetMessage(&msg, NULL, 0, 0))
	{
	   TranslateMessage(&msg);
	   DispatchMessage(&msg);
	}
	/* IF WE WERE USING REAL-TIME-RENDERING:
	  
	 
	while(msg.message != WM_QUIT)
	{
		if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			
		}
	}
	
	*/
	
}

LRESULT CALLBACK MainWindowProc(HWND mainWindow, UINT message, WPARAM wParam, LPARAM lParam) 
{
	unsigned short x, y;
	unsigned short i;
	
	RECT tb;
	tb.top = 5;
	tb.bottom = 55;
	tb.left = 5;
	tb.right = 55 + NUM_TOOLBAR_BUTTONS * 55;

	OPENFILENAME fileToOpen;
	char fileName[256];
	
	switch(message)
	{
	case WM_CREATE:
		printevent(STR_GUICREATED);
		
		// A. CREATING GDI OBJECTS
		
		GDIInit(mainWindow);
		
		// B. TIMERS
		
		SetTimer(mainWindow, TMR_SCROLL, 150, TimerScroll);
		SetTimer(mainWindow, TMR_LAMP, 1000, TimerLamp);
		
		SetUpCoordinates(mainWindow);
		
		break;
		
	case WM_SIZE:
		SetUpCoordinates(mainWindow);
		if((LOWORD(lParam) < 800 || HIWORD(lParam) < 400) && wParam != SIZE_MINIMIZED)
		{
			SetWindowPos(mainWindow, HWND_TOP, 0, 0, 820, 480, SWP_NOMOVE | SWP_NOZORDER | SWP_SHOWWINDOW);
			printevent(STR_RESIZEERROR);
		}
		
		RegistersPos = 0;
		
		break;

	case WM_KEYDOWN:
		switch(wParam)
		{
		case VK_F1:
			ShowHelpDialog(mainWindow);
			break;
		case VK_F7:
			DisasmPos = -1;
			PSPSingleStep();
			UpdateCPUDisplays(mainWindow);
			break;
		case VK_F9:
			DisasmPos = -1;
			if(GetCPUState() == CPU_STATE_STOPPED)
				PSPStart();
			else
				PSPResume();
			UpdateCPUDisplays(mainWindow);
			break;
		case VK_F10:
			PSPReset();
			UpdateCPUDisplays(mainWindow);
			break;
		case VK_F11:
			PSPPause();
			UpdateCPUDisplays(mainWindow);
			break;
		case VK_F12:
			ExtendedView = !ExtendedView;
			SetUpCoordinates(mainWindow);
			InvalidateRgn(mainWindow, NULL, TRUE);
			UpdateWindow(mainWindow);
			if(ExtendedView)
				printevent("Switched to extended view.");
			else
				printevent("Switched to normal view.");
			break;
		default:
			break;
		}
	break;
	
	case WM_PAINT:
		
		RegistersToZoom = false;
		
		// 1. TOOL BAR, STATUS BAR
		
		GDIBegin(mainWindow);
		GDIPaintToolBar();
		GDIPaintStatusBar();
			
		// 2. PSP DISPLAY
		
		GDIPaintDisplay();
		
		if(ExtendedView)
		{
			// 3. SUBWINDOW 'CPU REGISTERS'			
			
			GDIPaintRegisters();

			// 4. SUBWINDOW 'MEMORY STATUS'
			
			GDIPaintMemory();
			
			// 5. SUBWINDOW 'DISASSEMBLY'
			
			GDIPaintDisasm();
		}
		
		GDIEnd(mainWindow);
		
		break;
		
	case WM_COMMAND:
		if(HIWORD(wParam) == 0)
		{
			switch(LOWORD(wParam))
			{
			case IDM_OPEN:
				ZeroMemory(&fileToOpen, sizeof(fileToOpen));
				fileToOpen.lStructSize = sizeof(OPENFILENAME);
				fileToOpen.lpstrFileTitle = NULL;
				fileToOpen.nMaxFileTitle = 0;
				fileToOpen.lpstrInitialDir = NULL;
				fileToOpen.lpstrFile = fileName;
				fileToOpen.lpstrFile[0] = '\0';
				fileToOpen.nMaxFile = sizeof(fileName);
				fileToOpen.lpstrFilter = "PBP files (*.pbp)\0*.PBP\0Playstation relocable executable (*.prx)\0*.PRX\0BIN images (*.bin)\0*.BIN\0ISO Images (*.iso)\0*.ISO\0All files (*.*)\0*.*\0";
				fileToOpen.nFilterIndex = 1;
				fileToOpen.hwndOwner = mainWindow;
				fileToOpen.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
				if(GetOpenFileName(&fileToOpen))
					LoadFile(fileToOpen.lpstrFile);
				break;
			case IDM_QUIT:
				PostQuitMessage(0);
				break;
			case IDM_START:
				DisasmPos = -1;
				if(GetCPUState() == CPU_STATE_STOPPED)
					PSPStart();
				else
					PSPResume();
				UpdateCPUDisplays(mainWindow);
				break;
			case IDM_PAUSE:
				PSPPause();
				UpdateCPUDisplays(mainWindow);
				break;
			case IDM_STOP:
				PSPReset();
				UpdateCPUDisplays(mainWindow);
				break;
			case IDM_STEP:
				DisasmPos = -1;
				PSPSingleStep();
				UpdateCPUDisplays(mainWindow);
				break;
			case IDM_MANAGEBREAKPOINTS:
				break;
			case IDM_REMOVEBREAKPOINTS:
				break;
			case IDM_WEB:
				
				break;
			case IDM_ABOUT:
				ShowHelpDialog(mainWindow);
				break;
			default:
				break;
			}
		}
		break;
		
	case WM_LBUTTONDOWN:
		x = LOWORD(lParam);
		y = HIWORD(lParam);
		
		if(x >= _RRegisters1.left && x <= _RRegisters1.right && RegistersPos
				&& y >= _RRegisters1.top && y <= _RRegisters1.bottom)
		{
			RegistersPos--;

			InvalidateRect(mainWindow, &RRegisters, FALSE);
			UpdateWindow(mainWindow);
			
			ScrollReg = -1;
		}
		if(x >= _RRegisters2.left && x <= _RRegisters2.right && RegistersToZoom
				&& y >= _RRegisters2.top && y <= _RRegisters2.bottom)
		{
			RegistersPos++;

			InvalidateRect(mainWindow, &RRegisters, FALSE);
			UpdateWindow(mainWindow);
			
			ScrollReg = 1;
		}
		if(x >= _RDisasm1.left && x <= _RDisasm1.right && DisasmPos > 0
				&& y >= _RDisasm1.top && y <= _RDisasm1.bottom)
		{
			DisasmPos -= 4;

			InvalidateRect(mainWindow, &RDisasm, FALSE);
			UpdateWindow(mainWindow);
			ScrollDisasm = -1;
		}
		if(x >= _RDisasm2.left && x <= _RDisasm2.right
				&& y >= _RDisasm2.top && y <= _RDisasm2.bottom)
		{
			DisasmPos += 4;

			InvalidateRect(mainWindow, &RDisasm, FALSE);
			UpdateWindow(mainWindow);
			ScrollDisasm = 1;
		}
		
		for(i = 0; i < NUM_TOOLBAR_BUTTONS; i++)
		{
			if(x >= 5 + i * 55 && x <= 55 + i * 55
					&& y >= 5 && y <= 55)
			{
				ClickButton = i + 1;
				InvalidateRect(mainWindow, &tb, FALSE);
				UpdateWindow(mainWindow);
				
				switch(i)
				{
				case 0:
					DisasmPos = -1;
					if(GetCPUState() == CPU_STATE_STOPPED)
						PSPStart();
					else
						PSPResume();
					break;
				case 1:
					PSPPause();
					break;
				case 2:
					PSPReset();
					break;
				default:
					break;
				}
				UpdateCPUDisplays(mainWindow);
			}
		}
		
		break;
			
	case WM_LBUTTONUP:
		ScrollReg = 0;
		ScrollDisasm = 0;
		ClickButton = 0;
		InvalidateRect(mainWindow, &tb, FALSE);
		UpdateWindow(mainWindow);
		break;
		
	case WM_MOUSEMOVE:
		x = LOWORD(lParam);
		y = HIWORD(lParam);
		if(OverButton)
		{
			OverButton = 0;
			InvalidateRect(mainWindow, &tb, FALSE);
		}
		
		OverButton = 0;
		
		for(i = 0; i < NUM_TOOLBAR_BUTTONS; i++)
		{
			
			if(x >= 5 + i * 55 && x <= 55 + i * 55
					&& y >= 5 && y <= 55)
			{
				OverButton = i + 1;
				InvalidateRect(mainWindow, &tb, FALSE);
				UpdateWindow(mainWindow);
			}
		}
		
		break;
		
	case WM_CLOSE:
		KillTimer(mainWindow, TMR_SCROLL);
		KillTimer(mainWindow, TMR_LAMP);
		
		GDICleanUp(mainWindow);
		
		printevent("Emulator window has been closed.");
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(mainWindow, message, wParam, lParam);
	}

	return DefWindowProc(mainWindow, message, wParam, lParam);
}

void CreateMainWin()
{
	WNDCLASSEX mwnd;
	mwnd.cbClsExtra		= 0;
	mwnd.cbSize			= sizeof(WNDCLASSEX);
	mwnd.cbWndExtra		= 0;
	mwnd.hbrBackground	= (HBRUSH)GetStockObject(DKGRAY_BRUSH);
	mwnd.hCursor		= LoadCursor(NULL, IDC_ARROW);
	mwnd.hIcon			= LoadIcon(NULL, MAKEINTRESOURCE(IDI_APPICON));
	mwnd.hIconSm		= NULL;
	mwnd.hInstance		= NULL;
	mwnd.lpfnWndProc	= MainWindowProc;
	mwnd.lpszClassName	= "MainWindowPSP";
	mwnd.lpszMenuName	= MAKEINTRESOURCE(IDM_MAINMENU);
	mwnd.style			= CS_OWNDC | CS_HREDRAW | CS_VREDRAW;

	RegisterClassEx(&mwnd);

	CreateWindowEx(	0,
							"MainWindowPSP",
							"MFZPSP",
							WS_VISIBLE | WS_TILEDWINDOW,
							100, 100,
							800, 600,
							NULL,
							NULL,
							NULL,
							NULL);
}

void CreateToolBar(HWND win)
{
	unsigned short i;
	for(i = 0; i < NUM_TOOLBAR_BUTTONS; i++)
	{
		ToolBar[i] = CreateWindowEx(0,
				"BUTTON",
				"",
				WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
				5 + i * 45, 5,
				40, 40,
				win,
				NULL,
				(HINSTANCE)GetWindowLong(win, GWL_HINSTANCE),
				NULL);
	}
	
}

void SetUpCoordinates(HWND win)
{
	GetClientRect(win, &RClientArea);
	RStatusBar = RClientArea;
	RStatusBar.top = RStatusBar.bottom - 21;

	if(ExtendedView)
	{
		RDisplay = RClientArea;
		RDisplay.left = RDisplay.right - 490;
		RDisplay.right -= 10;
		RDisplay.top += 60;
		RDisplay.bottom = RDisplay.top + 272;
		
		if(RClientArea.right - RClientArea.left > 999)
		{
			RMemory = RDisplay;
			RMemory.top = RDisplay.bottom + 10;
			RMemory.bottom = RClientArea.bottom - 30;
			
			RRegisters = RClientArea;
			RRegisters.right = RMemory.left - 10;
			RRegisters.left = RRegisters.right - 170;
			RRegisters.top += 60;
			RRegisters.bottom -= 30;
			
			RDisasm = RRegisters;
			RDisasm.left = RClientArea.left + 10;
			RDisasm.right = RRegisters.left - 10;
		}
		else
		{
			RDisasm = RClientArea;
			RDisasm.left += 10;
			RDisasm.right = RDisplay.left - 10;
			RDisasm.top += 60;
			RDisasm.bottom -= 30;
			
			RRegisters = RClientArea;
			RRegisters.left = RDisplay.left;
			RRegisters.right -= 320;
			RRegisters.top = RDisplay.bottom + 10;
			RRegisters.bottom -= 30;
			
			RMemory = RRegisters;
			RMemory.left = RRegisters.right + 10;
			RMemory.right = RClientArea.right - 10;
		}
	}
	else
	{
		RDisplay.left = (RClientArea.right - RClientArea.left) / 2 - 240;
		RDisplay.right = RDisplay.left + 480;
		RDisplay.top = (RClientArea.bottom - RClientArea.top) / 2 - 136;
		RDisplay.bottom = RDisplay.top + 272;
	}
}

void GDIInit(HWND win)
{
	GDIDevice = GetDC(win);
			
	FStatusBar = CreateFont(15, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
			CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, NULL);
	FTitle = CreateFont(18, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
			CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, NULL);
	FHex = CreateFont(15, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
			CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, FIXED_PITCH, NULL);
	FMonospace = CreateFont(15, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
			CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, FIXED_PITCH, NULL);
	
	BLightBlue = CreateSolidBrush(MFZ_LIGHTBLUE);
	BDarkBlue = CreateSolidBrush(MFZ_DARKBLUE);
	BLightGray = CreateSolidBrush(MFZ_LIGHTGRAY);
	BMediumGray = CreateSolidBrush(MFZ_MEDIUMGRAY);
	BRed = CreateSolidBrush(MFZ_RED);
	BYellow = CreateSolidBrush(MFZ_YELLOW);
	BBlack = CreateSolidBrush(MFZ_BLACK);
	
	HDC refDC = GetDC(NULL);
	BMPPalette = CreateHalftonePalette(refDC);
	ReleaseDC(NULL, refDC);
	
	if(!GDILoadBMP("gfx/StatuslightYellow.bmp", &IStatusYellow)
			|| !GDILoadBMP("gfx/StatuslightRed.bmp", &IStatusRed)
			|| !GDILoadBMP("gfx/StatuslightBlue.bmp", &IStatusBlue)
			|| !GDILoadBMP("gfx/StatuslightGreen.bmp", &IStatusGreen)
			|| !GDILoadBMP("gfx/StatuslightGrey.bmp", &IStatusGray)
			|| !GDILoadBMP("gfx/PlayActive.bmp", &IPlayA)
			|| !GDILoadBMP("gfx/PlayInActive.bmp", &IPlayI)
			|| !GDILoadBMP("gfx/PauseActive.bmp", &IPauseA)
			|| !GDILoadBMP("gfx/PauseInActive.bmp", &IPauseI)
			|| !GDILoadBMP("gfx/StopActive.bmp", &IStopA)
			|| !GDILoadBMP("gfx/StopInActive.bmp", &IStopI)
			|| !GDILoadBMP("gfx/OpenActive.bmp", &IOpenA)
			|| !GDILoadBMP("gfx/OpenInActive.bmp", &IOpenI))
	{
		printerror("Could not load bitmap!");
	}
}

void GDIBegin(HWND win)
{
	BeginPaint(win, &PaintStruct);
}

void GDIPaintToolBar()
{
	switch(ClickButton)
	{
	case 1:
		GDIShowBMP(IPlayA, 6, 6);
		GDIShowBMP(IPauseI, 60, 5);
		GDIShowBMP(IStopI, 115, 5);
		break;
	case 2:
		GDIShowBMP(IPlayI, 5, 5);
		GDIShowBMP(IPauseA, 61, 6);
		GDIShowBMP(IStopI, 115, 5);
		break;
	case 3:
		GDIShowBMP(IPlayI, 5, 5);
		GDIShowBMP(IPauseI, 60, 5);
		GDIShowBMP(IStopA, 116, 6);
		break;
	default:
		if(OverButton == 1)
		GDIShowBMP(IPlayA, 5, 5);
		else
			GDIShowBMP(IPlayI, 5, 5);
		if(OverButton == 2)
			GDIShowBMP(IPauseA, 60, 5);
		else
			GDIShowBMP(IPauseI, 60, 5);
		if(OverButton == 3)
			GDIShowBMP(IStopA, 115, 5);
		else
			GDIShowBMP(IStopI, 115, 5);
		break;
	}
}

void GDIPaintStatusBar()
{
	char status2[17] = "WAITING FOR CPU";
	char status3[8] = "STOPPED";
	char status4[8] = "RUNNING";
	char status5[7] = "PAUSED";
	char status6[6] = "READY";
	char* st;
	
	int cpuState = GetCPUState();
	
	LONG x = RStatusBar.right - 20;
	LONG y = RStatusBar.top + 1;
	
	FillRect(GDIDevice, &RStatusBar, BLightGray);

	SelectObject(GDIDevice, FStatusBar);
	SetTextColor(GDIDevice, MFZ_BLACK);
	SetBkColor(GDIDevice, MFZ_LIGHTGRAY);
	ExtTextOut(GDIDevice, RStatusBar.left + 2, RStatusBar.top + 4,
			ETO_OPAQUE, NULL, STR_READY, STR_READY_L, NULL);
	
	switch(cpuState) // The emulator status (waiting, stopped or running).
	{
	case CPU_STATE_STOPPED:
		st = status3;
		GDIShowBMP(IStatusRed, x, y);
		break;
	case CPU_STATE_RUNNING:
		st = status4;
		GDIShowBMP(IStatusGreen, x, y);
		break;
	case CPU_STATE_PAUSED:
		st = status5;
		BlinkEnabled = true;
		if(Blinking)
		{
			GDIShowBMP(IStatusYellow, x, y);
		}
		else
			GDIShowBMP(IStatusGray, x, y);
		break;
	case CPU_STATE_READY:
		st = status6;
		BlinkEnabled = true;
		if(Blinking)
			GDIShowBMP(IStatusBlue, x, y);
		else
			GDIShowBMP(IStatusGray, x, y);
		break;
	default:
		st = status2;
		break;
	}

	ExtTextOut(GDIDevice, RStatusBar.right - 150, RStatusBar.top + 4, ETO_OPAQUE, NULL,
				st, strlen(st), NULL);
}

void GDIPaintDisplay()
{
	FillRect(GDIDevice, &RDisplay, BBlack);
}

void GDIPaintRegisters()
{
	char value[11];
	int cpuState = GetCPUState();
	
	SelectObject(GDIDevice, FTitle);
	SetBkColor(GDIDevice, MFZ_MEDIUMGRAY);

	FillRect(GDIDevice, &RRegisters, BMediumGray);
	RECT _RRegisters = RRegisters;
	_RRegisters.bottom = _RRegisters.top + 22;
	FillRect(GDIDevice, &_RRegisters, BLightBlue);
	SetBkColor(GDIDevice, MFZ_LIGHTBLUE);
	ExtTextOut(GDIDevice, RRegisters.left + 4, RRegisters.top + 4, ETO_OPAQUE, NULL, "Registers", 9, NULL);
	SetBkColor(GDIDevice, MFZ_MEDIUMGRAY);
	
	if(cpuState == CPU_STATE_RUNNING)
	{
		SetTextColor(GDIDevice, MFZ_RED);
		ExtTextOut(GDIDevice, RRegisters.left + 4, RRegisters.top + 22, ETO_OPAQUE, NULL,
				"The CPU is running", 18, NULL);
		SetTextColor(GDIDevice, 0);
	}
	else
	{
		unsigned short i;
		
		SetTextColor(GDIDevice, MFZ_DARKBLUE);
		SelectObject(GDIDevice, FMonospace);
		for(i = 0; i < 32 - RegistersPos; i++)
		{
			if(RRegisters.top + 22 + i * 12 < RRegisters.bottom - 14)
			{
				ExtTextOut(GDIDevice, RRegisters.left + 4, RRegisters.top + 22 + i * 12, ETO_OPAQUE, NULL,
						GetRegString(RegistersPos + i), STR_REG_L, NULL);
			}
		}
		SetTextColor(GDIDevice, MFZ_RED);
		SelectObject(GDIDevice, FHex);
		for(i = 0; i < 32 - RegistersPos; i++)
		{
			if(RRegisters.top + 22 + i * 12 < RRegisters.bottom - 14)
			{
				GetCPURegisterText(RegistersPos + i, value);
				if(oldRegister[RegistersPos + i] != GetCPURegister(RegistersPos + i))
					SetTextColor(GDIDevice, MFZ_ORANGE);
				oldRegister[RegistersPos + i] = GetCPURegister(RegistersPos + i);
				ExtTextOut(GDIDevice, RRegisters.left + 80, RRegisters.top + 22 + i * 12, ETO_OPAQUE, NULL,
						value, 10, NULL);
			}
			else
				RegistersToZoom = true;
			SetTextColor(GDIDevice, MFZ_RED);
		}
		SetTextColor(GDIDevice, 0);
		SelectObject(GDIDevice, FTitle);
		
		if(RegistersPos)
		{
			_RRegisters1 = RRegisters;
			_RRegisters1.left = _RRegisters1.right - 16;
			_RRegisters1.top += 22;
			_RRegisters1.bottom = _RRegisters1.top + 16;
			FillRect(GDIDevice, &_RRegisters1, BDarkBlue);
		}
		if(RegistersToZoom)
		{
			_RRegisters2 = RRegisters;
			_RRegisters2.left = _RRegisters2.right - 16;
			_RRegisters2.bottom = _RRegisters2.bottom;
			_RRegisters2.top = _RRegisters2.bottom - 16;
			FillRect(GDIDevice, &_RRegisters2, BDarkBlue);
		}
	}
}

void GDIPaintMemory()
{
	FillRect(GDIDevice, &RMemory, BMediumGray);
	RECT _RMemory = RMemory;
	_RMemory.bottom = _RMemory.top + 22;
	FillRect(GDIDevice, &_RMemory, BLightBlue);
	SetBkColor(GDIDevice, MFZ_LIGHTBLUE);
	ExtTextOut(GDIDevice, RMemory.left + 4, RMemory.top + 4, ETO_OPAQUE, NULL, "Memory", 6, NULL);
	SetBkColor(GDIDevice, MFZ_MEDIUMGRAY);
}

void GDIPaintDisasm()
{
	int cpuState = GetCPUState();
	
	FillRect(GDIDevice, &RDisasm, BMediumGray);
	RECT _RDisasm = RDisasm;
	_RDisasm.bottom = _RDisasm.top + 22;
	FillRect(GDIDevice, &_RDisasm, BLightBlue);
	SetBkColor(GDIDevice, MFZ_LIGHTBLUE);
	ExtTextOut(GDIDevice, RDisasm.left + 4, RDisasm.top + 4, ETO_OPAQUE, NULL, "Disassembly", 11, NULL);
	SetBkColor(GDIDevice, MFZ_MEDIUMGRAY);
	
	if(cpuState == CPU_STATE_RUNNING)
	{
		SetTextColor(GDIDevice, MFZ_RED);
		ExtTextOut(GDIDevice, RDisasm.left + 4, RDisasm.top + 22, ETO_OPAQUE, NULL,
				"The CPU is running", 18, NULL);
		SetTextColor(GDIDevice, 0);	
	}
	else
	{
		unsigned long i;
		unsigned long pc = GetProgramCounter();
		char pclist[9], operation[32], opcode[9], comment[32];
		SelectObject(GDIDevice, FMonospace);
		if(DisasmPos == -1)
		{
			DisasmPos = pc - 12*4;
			if(DisasmPos < 0)
				DisasmPos = 0;
		}
		for(i = 0; i < ((RDisasm.bottom - RDisasm.top - 28) / 12); i++)
		{
			/*if(pc == DisasmPos + i)
			{
				SetBkColor(GDIDevice, MFZ_YELLOW);
				RECT yellowGround = RDisasm;
				yellowGround.top = yellowGround.top + 22 + i * 12;
				yellowGround.bottom = yellowGround.top + 14;
				FillRect(GDIDevice, &yellowGround, BYellow);
			}*/
			GetCPUCode(DisasmPos + i*4, pclist, operation, opcode, comment);
			if(pc == DisasmPos + i*4)
			{
				SetTextColor(GDIDevice, MFZ_ORANGE);
			}
			else
			{
				SetTextColor(GDIDevice, MFZ_BLACK);
			}
			ExtTextOut(GDIDevice, RDisasm.left + 4, RDisasm.top + 22 + i * 12, ETO_OPAQUE, NULL,
					pclist, 8, NULL);
			if(pc == DisasmPos + i*4)
				SetTextColor(GDIDevice, MFZ_ORANGE);
			else
				SetTextColor(GDIDevice, MFZ_RED);
			ExtTextOut(GDIDevice, RDisasm.left + 70, RDisasm.top + 22 + i * 12, ETO_OPAQUE, NULL,
					operation, 8, NULL);
			if(pc == DisasmPos + i*4)
				SetTextColor(GDIDevice, MFZ_ORANGE);
			else
				SetTextColor(GDIDevice, MFZ_DARKBLUE);
			ExtTextOut(GDIDevice, RDisasm.left + 140, RDisasm.top + 22 + i * 12, ETO_OPAQUE, NULL,
					opcode, 8, NULL);
			if(pc == DisasmPos + i*4)
			{
				SetTextColor(GDIDevice, MFZ_ORANGE);
			}
			else
			{
				SetTextColor(GDIDevice, MFZ_DARKBLUE);
			}
			ExtTextOut(GDIDevice, RDisasm.left + 210, RDisasm.top + 22 + i * 12, ETO_OPAQUE, NULL,
					comment, 8, NULL);
			SetBkColor(GDIDevice, MFZ_MEDIUMGRAY);
		}
	}
	
	if(DisasmPos)
	{
		_RDisasm1 = RDisasm;
		_RDisasm1.left = _RDisasm1.right - 16;
		_RDisasm1.top += 22;
		_RDisasm1.bottom = _RDisasm1.top + 16;
		FillRect(GDIDevice, &_RDisasm1, BDarkBlue);
	}
	if(1)
	{
		_RDisasm2 = RDisasm;
		_RDisasm2.left = _RDisasm2.right - 16;
		_RDisasm2.bottom = _RDisasm2.bottom;
		_RDisasm2.top = _RDisasm2.bottom - 16;
		FillRect(GDIDevice, &_RDisasm2, BDarkBlue);
	}
}

void GDIEnd(HWND win)
{
	EndPaint(win, &PaintStruct);
}

void GDICleanUp(HWND win)
{
	ReleaseDC(win, GDIDevice);
	DeleteObject(FStatusBar);
	DeleteObject(FTitle);
	DeleteObject(FHex);
	DeleteObject(FMonospace);
	DeleteObject(BLightBlue);
	DeleteObject(BDarkBlue);
	DeleteObject(BLightGray);
	DeleteObject(BMediumGray);
	DeleteObject(BRed);
	DeleteObject(BBlack);
}

bool GDILoadBMP(LPTSTR file, HBITMAP *bitmap)
{
	*bitmap = (HBITMAP)LoadImage(NULL, file, IMAGE_BITMAP, 0, 0,
			LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
	if(*bitmap == NULL)
		return false;
	return true;
}

void GDIShowBMP(HBITMAP bitmap, LONG x, LONG y)
{
	BITMAP bm;
	HDC memDC;
	HBITMAP oldBitmap;
	HPALETTE oldPalette;
	
	GetObject(bitmap, sizeof(BITMAP), &bm);
	memDC = CreateCompatibleDC(GDIDevice);
	oldBitmap = (HBITMAP)SelectObject(memDC, bitmap);
	oldPalette = SelectPalette(GDIDevice, BMPPalette, FALSE);
	RealizePalette(GDIDevice);
	
	BitBlt(GDIDevice, x, y, bm.bmWidth, bm.bmHeight, memDC, 0, 0, SRCCOPY);
	
	SelectObject(memDC, oldBitmap);
	SelectPalette(GDIDevice, oldPalette, FALSE);
}


void ShowHelpDialog(HWND parent)
{
	MessageBox(parent, "This is the MFZPSP Emulator. Copyright 2008 Mauro Frischherz\n\nMauro Frischherz, Stefan Zurfluh",
			"About MFZPSP", MB_OK|MB_ICONINFORMATION);	
}

void UpdateCPUDisplays(HWND win)
{
	InvalidateRect(win, &RRegisters, FALSE);
	InvalidateRect(win, &RDisasm, FALSE);
	InvalidateRect(win, &RMemory, FALSE);
	InvalidateRect(win, &RStatusBar, FALSE);
	
	UpdateWindow(win);
}


VOID CALLBACK TimerScroll(HWND mainWindow, UINT message, UINT_PTR idEvent, DWORD dwTime)
{
	if(ScrollReg < 0 && RegistersPos)
	{
		if(ScrollReg-- < -3)
		{
			RegistersPos--;
			InvalidateRect(mainWindow, &RRegisters, FALSE);
			UpdateWindow(mainWindow);
		}
	}
	if(ScrollReg > 0 && RegistersToZoom)
	{
		if(ScrollReg++ > 3)
		{
			RegistersPos++;
			InvalidateRect(mainWindow, &RRegisters, FALSE);
			UpdateWindow(mainWindow);
		}
	}
	if(ScrollDisasm < 0 && DisasmPos > 0)
	{
		if(ScrollDisasm-- < -3)
		{
			DisasmPos -= 4;
			InvalidateRect(mainWindow, &RDisasm, FALSE);
			UpdateWindow(mainWindow);
		}
	}
	if(ScrollDisasm > 0)
	{
		if(ScrollDisasm++ > 3)
		{
			DisasmPos += 4;
			InvalidateRect(mainWindow, &RDisasm, FALSE);
			UpdateWindow(mainWindow);
		}
	}
}

VOID CALLBACK TimerLamp(HWND mainWindow, UINT message, UINT_PTR idEvent, DWORD dwTime)
{
	if(BlinkEnabled)
	{
		RECT _RStatusBar = RStatusBar;
		_RStatusBar.left = _RStatusBar.right - 20;
		Blinking = !Blinking;
		InvalidateRect(mainWindow, &_RStatusBar, FALSE);
		UpdateWindow(mainWindow);
	}
}

#endif
